package com.vhall.component.service.redpacket.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.redpacket.RedPacketMapper;
import com.vhall.component.entity.rebroadcast.RedPacketEntity;
import com.vhall.component.entity.redpacket.vo.OverBySourceIdReqVO;
import com.vhall.component.entity.redpacket.vo.RedPacketVO;
import com.vhall.component.entity.redpacket.vo.StatVo;
import com.vhall.component.service.redpacket.common.RedpacketConstants;
import com.vhall.component.service.redpacket.common.RefundStatus;
import com.vhall.component.service.redpacket.service.CacheService;
import com.vhall.component.service.redpacket.service.RedPacketRefundService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author xuyongzheng
 * @since 2021/3/20 21:48
 **/
@Slf4j
@Service
public class RedPacketRefundServiceImpl implements RedPacketRefundService {


    @Autowired
    private RedPacketMapper redPacketMapper;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private InnerPayService innerPayService;

    @Autowired
    private RedPacketStatServiceImpl statService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<RedPacketVO> overBySourceId(OverBySourceIdReqVO vo) {
        LambdaQueryWrapper<RedPacketEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RedPacketEntity::getAppId, vo.getAppId())
                .eq(RedPacketEntity::getRoomId, vo.getSourceId())
                .eq(RedPacketEntity::getPayStatus, 1)
                .eq(RedPacketEntity::getRefundStatus, 0)
                .eq(RedPacketEntity::getGiftType, vo.getGiftType())
                .eq(RedPacketEntity::getDeleted, RedpacketConstants.SOFT_DELETE);
        List<RedPacketEntity> redPackets = redPacketMapper.selectList(wrapper);
        if (redPackets.isEmpty()) {
            return Collections.emptyList();
        }
        List<RedPacketVO> list = new ArrayList<>();
        redPackets.forEach(packet -> list.add(refundRedPacket(packet)));
        log.info("退款4,{}", list);
        return list;
    }

    private RedPacketVO refundRedPacket(RedPacketEntity packet) {
        StatVo stat = updatePacketStat(packet);
        log.info("退款02,{}", stat);
        if (stat == null) {
            return null;
        }
        BigDecimal balance = packet.getAmount().subtract(stat.getGetAmount());
        LambdaUpdateWrapper<RedPacketEntity> update = Wrappers.lambdaUpdate();
        if (balance.compareTo(BigDecimal.ZERO) > 0) {
            Boolean result = innerPayService.payOrReturnRedPacketCallback(packet.getAppId(), packet.getAccountId(),
                    packet.getUuid(), balance, RedpacketConstants.RETURN_RED_PACKET_EVENT);

            log.info("退款3,result={}", result);
            if (Boolean.TRUE.equals(result)) {
                update.set(RedPacketEntity::getRefundStatus, RefundStatus.SUCCESS.getCode())
                        .set(RedPacketEntity::getCreatedAt, LocalDateTime.now())
                        .eq(RedPacketEntity::getId, packet.getId());
                redPacketMapper.update(null, update);
                packet.setRefundStatus(RefundStatus.SUCCESS.getCode());
            } else {
                update.set(RedPacketEntity::getRefundStatus, RefundStatus.FAIL.getCode())
                        .set(RedPacketEntity::getCreatedAt, LocalDateTime.now())
                        .eq(RedPacketEntity::getId, packet.getId());
                redPacketMapper.update(null, update);
                packet.setRefundStatus(RefundStatus.FAIL.getCode());
            }
        } else {
            balance = BigDecimal.ZERO;
            update.set(RedPacketEntity::getRefundStatus, RefundStatus.SUCCESS.getCode())
                    .set(RedPacketEntity::getCreatedAt, LocalDateTime.now())
                    .eq(RedPacketEntity::getId, packet.getId());
            redPacketMapper.update(null, update);
            packet.setRefundStatus(RefundStatus.SUCCESS.getCode());
        }

        cacheService.clearRedPacketCache(packet);
        packet.setRefundAmount(balance);

        RedPacketVO result = new RedPacketVO();
        BeanUtils.copyProperties(packet, result);
        return result;
    }

    private StatVo updatePacketStat(RedPacketEntity redPacket) {
        RedPacketVO redPacketVO = new RedPacketVO();
        BeanUtils.copyProperties(redPacket, redPacketVO);
        StatVo stat = statService.statByRedPacketId(redPacket.getAppId(),
                redPacket.getId(), redPacketVO);
        LambdaUpdateWrapper<RedPacketEntity> update = Wrappers.lambdaUpdate();
        update.set(stat.getJoinedUserCount() != null, RedPacketEntity::getJoinedUserCount, stat.getJoinedUserCount())
                .set(stat.getGetUserCount() != null, RedPacketEntity::getGetUserCount, stat.getGetUserCount())
                .set(stat.getGetAmount() != null, RedPacketEntity::getGetAmount, stat.getGetAmount())
                .set(RedPacketEntity::getUpdatedAt, LocalDateTime.now())
                .eq(RedPacketEntity::getId, redPacket.getId())
                .eq(RedPacketEntity::getAppId, redPacket.getAppId());
        if (redPacketMapper.update(null, update) == 0) {
            return null;
        }
        return stat;
    }

}
